home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Libris Britannia 4
/
science library(b).zip
/
science library(b)
/
PROGRAMM
/
DB_CLIPP
/
2614.ZIP
/
50ERRS.ZIP
/
S87ERMAP.PRG
< prev
next >
Wrap
Text File
|
1990-10-05
|
13KB
|
359 lines
/**************************************************************************
*
* Module name:
*
* S87ErMap.prg
*
* What it does:
*
* Clipper 5.0 routine to re-package 5.0 Error Handling conventions
* to those compatible with Summer '87. This allows you to compile
* and link your Summer '87 applications with Clipper 5.0 and
* retain your existing Summer '87 modifications to the six UDF()s
* in ErrorSys.prg. You may select either Summer '87 or
* Clipper 5.0 Error Handling for your program at run-time via a
* DOS 'SET ERRORSYS=' command.
*
* This routine demonstrates the power and flexibility of Clipper 5.0
* nested arrays, ErrorBlock() posting, code blocks, the EVAL()
* function, table look-up with ASCAN(), the use of optional code
* blocks with array iterator functions and how code blocks and
* UDF()s can be chained as RETURN arguments. The actual mapping
* part of this routine is only four (4) lines. It could have
* been written in two (2) lines!
*
* How to compile it:
*
* Clipper S87ErMap /n/w/a
*
* How to link it:
*
* Link in S87ErMap.obj with your application
*
* How to use it:
*
* Insert the following line at the start of your program to call
* the UDF() in this routine that will post a new ErrorBlock():
*
* S87ErrorSys()
*
* To request Summer '87 Error Handling at run-time:
*
* SET ERRORSYS=S87
*
* To request Clipper 5.0 Error Handling at run-time:
*
* SET ERRORSYS=5.0 (default)
*
* Written by:
*
* Philip H. Schwartz
* Vertical Management Systems, Inc.
* POB 90243
* Gainesville, FL 32607
* Compuserve: 72537,3261
*
* Written on:
*
* June 3, 1990 (for Palm Desert DevCon)
*
* Last updated on:
*
* October 5, 1990 (for Orlando Devcon)
*
* Rights:
*
* (c) 1990 Philip H. Schwartz
*
* Release:
*
* Written for tutorial purposes and non-commercial distribution
* rights assigned to Clipper developer community. May be distributed
* in this form without charge. Commercial and publishing rights
* reserved.
*
* Warranty:
*
* None.
*
* Comments:
*
* Additional material (text and code) will be available
* in a forthcoming monograph on the Clipper 5.0 Error System
* and in a series of Nantucket News articles.
*
**************************************************************************/
#include "error.ch" // 5.0 EG_xxxx generic code definitions
#define GENCODE 1 // Column in mapping array of gencode() error
#define CODEBLOCK 2 // Column in mapping array of code block id
#define CALL_LEVEL 3 /* This is how far to go back in the
ProcName() and ProcLine() stack
to find the procedure that generated
the error. We must pass the procedure
name and procedure line to the S'87
UDF()s.
Level 1 - The error handler we are now in.
Level 2 - The code block statement that
set up the call to the error
handler function: '(b)procname'.
Level 3 - The application code or
Nantucket routine in which the
error occurred. This is where
we really want to be, so we
set the CALL_LEVEL constant to
3.
*/
***
* These preprocessor constants are used to map a Clipper 5.0 error
* condition (as defined by include file "error.ch") to the S'87 UDF
* that would normally be responsible.
*
* The following definitions identify the code blocks that will
* call the S'87 error functions with the proper parameters.
***
#define EXPR_ERROR 1 // 1 - Expression Error
#define UNDEF_ERROR 2 // 2 - Undefined Error
#define OPEN_ERROR 3 // 3 - Open Error
#define DB_ERROR 4 // 4 - Database Error
#define PRINT_ERROR 5 // 5 - Print Error
#define MISC_ERROR 6 // 6 - Miscellaneous Error
#define UNKNOWN_ERROR 7 // 7 - Unknown Clipper 5.0 e:gencode()
/* This is not one of the S'87 UDF()s.
We will stuff the unknown gencode in
the description text that we pass to
MISC_ERROR. */
STATIC bDefaultHandler /* This is where we save the default
Clipper 5.0 Error Code Block. We mark
it STATIC so it can be visible throughout
the module (prg). */
***
* FUNCTION S87ErrorSys()
*
* The only purpose of S87ErrorSys() is to provide a simple calling
* interface to the mapping function. Rather than ask the main
* application program to install a new ErrorBlock() and keep track
* of the default 5.0 handler, it is simpler to insert a one line
* function call in the main program.
*
* This function will install the new ErrorBlock() and save the
* default Clipper 5.0 Error Handler. The function is purposely not
* marked STATIC so that it can be visible to the main program.
***
FUNCTION S87ErrorSys
bDefaultHandler := ErrorBlock( {|e| S87to50( e ) } )
RETURN NIL
***
* FUNCTION S87to50()
*
* This is the function that maps the Clipper 5.0 Error
* Object to the calling sequences used in S'87.
*
* Note:
* (1) the function is marked STATIC to prevent outside calls.
* (2) the Error Object (e) is passed as a formal parameter.
***
STATIC FUNCTION S87to50( e )
LOCAL aS87UdfTable // array of code blocks to call S'87 UDF()s
LOCAL aS87MapTable // array to map gencode to S'87 UDF()s
LOCAL nS87udf // id of code block to handle current error
***
* The following code checks to see if 5.0 or S'87 Error Handling
* conventions are to be followed. If 5.0 is selected, the
* default Clipper 5.0 Error Handler is EVAL()uated, passing along
* the current Error Object (e). Otherwise, we continue with the
* S'87 re-mapping.
***
IF "5.0" $ GETE( "ERRORSYS" ) .OR. !( "S87" $ UPPER( GETE( "ERRORSYS" ) ) )
RETURN( EVAL( bDefaultHandler, e ) )
ENDIF
/***
* Background information on how Summer '87 performed
* Error Handling.
***
These are the six UDF()s in S'87 that are located in the
ErrorSys.prg module. Each one handles a particular set of
error situations.
Expr_Error( Name, Line, Info, Model, _1, _2, _3 )
Undef_Error( Name, Line, Info, Model, _1 )
Open_Error( Name, Line, Info, Model, _1 )
DB_Error( Name, Line, Info )
Print_Error( Name, Line )
Misc_Error( Name, Line, Info, Model )
These parameters have the following meaning:
Name procedure/udf/clipper library routine
Line source line (0 for most library routines)
Info error description text
Model model of expression in which error occurred,
e.g. if error occurred during ADD of
two numbers, the model would be "_1+_2". The
model parameter was never consistently
implemented in S'87 and is of limited use. In
most cases, we will map the 5.0 e:operation()
instance variable to the S'87 model parameter.
_1,_2,_3 arguments that are symbols in model statement,
e.g. if error occurred during 6+"4",
_1 would equal numeric 6 and _2 would equal
character string "4". In Summer '87 it was
necessary to check PCOUNT() on entry to UDF to
check total number of arguments passed.
Parameters that are missing in 5.0 will be
replaced with a null string ("") before calling
the S'87 error functions.
***/
***
* This is an array of code blocks that set up the arguments
* for the Summer '87 error handling functions. The argument list
* to the code block is NULL in each case since the Error Object
* instance variables will be passed to the S'87 routines already
* resolved.
*
* Note: The Clipper 5.0 documentation incorrectly refers to
* instance variable 'ARGS'. This array of optional arguments
* was changed to PARAMS between the BETA testing of 5.0 and its
* production release.
*
***
aS87UdfTable := ;
{ { || Expr_Error( ProcName( CALL_LEVEL ), ProcLine( CALL_LEVEL ), ;
e:description(), e:operation(), ParamsCheck( e:params(), 1 ), ;
ParamsCheck( e:params(), 2 ), ParamsCheck( e:params(), 3 ) ) }, ;
{ || Undef_Error( ProcName( CALL_LEVEL ), ProcLine( CALL_LEVEL ), ;
e:description, "", e:operation() ) }, ;
{ || Open_Error( ProcName( CALL_LEVEL ), ProcLine( CALL_LEVEL ), ;
e:description(), e:operation(), e:filename() ) }, ;
{ || DB_Error( ProcName( CALL_LEVEL ), ProcLine( CALL_LEVEL ), ;
e:description() ) }, ;
{ || Print_Error( ProcName( CALL_LEVEL ), ProcLine( CALL_LEVEL ) ) }, ;
{ || Misc_Error( ProcName( CALL_LEVEL ), ProcLine( CALL_LEVEL ), ;
e:description(), e:operation() ) }, ;
{ || Misc_Error( ProcName( CALL_LEVEL ), ProcLine( CALL_LEVEL ), ;
e:description() + " - gencode[" + LTRIM( STR( e:gencode() ) ) + "]", ;
e:operation() ) } }
***
* This is our Summer '87 Error Mapping Table. This is a
* nested array that is set up as a 29 x 2 table. The first
* column contains one of the Generic error codes found in
* "error.ch". The second column identifies which code block in
* the code block table is responsible for calling the associated
* S'87 error function.
*
* As the "error.ch" include file grows in new 5.0 releases,
* just make a corresponding entry in the mapping table below.
*
*--------------------------------------------------------------------
* 5.0 Gencode S'87 UDF() Identifier
*--------------------------------------------------------------------
aS87MapTable := { { EG_ARG, EXPR_ERROR }, ;
{ EG_BOUND, EXPR_ERROR }, ;
{ EG_STROVERFLOW, EXPR_ERROR }, ;
{ EG_NUMOVERFLOW, EXPR_ERROR }, ;
{ EG_ZERODIV, EXPR_ERROR }, ;
{ EG_NUMERR, EXPR_ERROR }, ;
{ EG_SYNTAX, UNDEF_ERROR } ,;
{ EG_COMPLEXITY, UNDEF_ERROR }, ;
{ EG_MEM, UNDEF_ERROR }, ;
{ EG_NOFUNC, UNDEF_ERROR }, ;
{ EG_NOMETHOD, UNDEF_ERROR }, ;
{ EG_NOVAR, UNDEF_ERROR }, ;
{ EG_OPEN, OPEN_ERROR }, ;
{ EG_NOALIAS, DB_ERROR }, ;
{ EG_CREATE, DB_ERROR }, ;
{ EG_CLOSE, DB_ERROR }, ;
{ EG_READ, DB_ERROR }, ;
{ EG_WRITE, DB_ERROR }, ;
{ EG_SHARED, DB_ERROR }, ;
{ EG_UNLOCKED, DB_ERROR }, ;
{ EG_READONLY, DB_ERROR }, ;
{ EG_PRINT, PRINT_ERROR }, ;
{ EG_UNSUPPORTED, MISC_ERROR }, ;
{ EG_LIMIT, MISC_ERROR }, ;
{ EG_CORRUPTION, MISC_ERROR }, ;
{ EG_DATATYPE, MISC_ERROR }, ;
{ EG_DATAWIDTH, MISC_ERROR }, ;
{ EG_NOTABLE, MISC_ERROR }, ;
{ EG_NOORDER, MISC_ERROR } }
***
* We use ASCAN() to locate the correct gencode entry in the
* mapping table. The code block tells ASCAN() that we are
* looking for the row in the mapping table that contains an entry
* for the gencode associated with the current Error Object.
* Since the array is nested, we use the GENCODE constant to identify
* the column that contains the gencode (column 1).
***
nS87udf := ASCAN( aS87MapTable, {|arr| arr[GENCODE] == e:gencode()} )
***
* Now we know the id of the code block that will set up the
* parameters for a call to the appropriate S'87 UDF(). We use
* the id to index into the code block table and EVAL()uate the
* code block. Since S'87 error functions know nothing about
* the Clipper 5.0 Error Object, and the argument portion of the
* code block (||) is null, it is not necessary to pass the
* Error Object in the EVAL().
*
* Here's what happens:
*
* The S'87 error UDF() will either quit, break or return a
* logical value (T/F). The EVAL() function will pass this logical
* value back to the Clipper 5.0 low-level error routines via the
* RETURN().
*
* If the gencode() was not found in the mapping table, we will call
* the S'87 Misc_Error() function with the unknown gencode() added
* to the the Nantucket-supplied error description.
***
RETURN( ;
EVAL( ;
aS87UdfTable[ ;
aS87MapTable[ if( nS87udf == 0, UNKNOWN_ERROR, nS87udf ), CODEBLOCK ] ;
] ;
) ;
)
/***
* This function tests for the presence of an optional e:params()
* instance variable.
*
* Note:
* (1) e:params() must be an Array
* (2) a null string is returned if the element does not exist
*/
STATIC FUNCTION ParamsCheck( aArgs, nPosition )
IF VALTYPE( aArgs ) == "A"
RETURN( IF( nPosition <= LEN( aArgs ), aArgs[ nPosition ], "" ) )
ENDIF
RETURN( "" )
/*eof*/